package api

import (
	"context"
	"encoding/json"
	"fmt"
	"github.com/gin-gonic/gin"
	"github.com/wechatpay-apiv3/wechatpay-go/core/notify"
	"github.com/wechatpay-apiv3/wechatpay-go/services/payments"
	"io/ioutil"
	"kuangstudy-mall/apis/order-web/tools"
	utils2 "kuangstudy-mall/apis/order-web/utils"
	"log"
	"net/http"
	"time"

	"github.com/wechatpay-apiv3/wechatpay-go/core"
	"github.com/wechatpay-apiv3/wechatpay-go/core/option"
	"github.com/wechatpay-apiv3/wechatpay-go/services/payments/jsapi"
	"github.com/wechatpay-apiv3/wechatpay-go/utils"
)

type WeixinJSPayApi struct {
	BaseApi
}

type Params struct {
	GoodsId uint64 `json:"goodsId"`
	OpenId  string `json:"openId"`
}

type AttchParams struct {
	UserId uint64 `json:"userId"`
	Opid   uint64 `json:"opid"`
	VipId  uint64 `json:"vipId"`
	Type   string `json:"type"`
	Price  string `json:"price"`
}

type QueryParams struct {
	OutTradeNo string `json:"outTradeNo"`
}

const (
	code2sessionURL = "https://api.weixin.qq.com/sns/jscode2session?appid=%s&secret=%s&js_code=%s&grant_type=authorization_code"
	appID           = "wx2130f87b8f96cff7"
	appSecret       = "94430458b92e3b8feb50a3464a78aa45"
)

/*
*
获取openid的方法
*/
func (api *WeixinJSPayApi) GendWxAuthAPI(ctx *gin.Context) {
	code, _ := ctx.GetQuery("code")
	url := fmt.Sprintf(code2sessionURL, appID, appSecret, code)
	resp, err := http.DefaultClient.Get(url)
	if err != nil {
		api.FailCodeMsgAny(901, "", ctx)
		return
	}
	var wxMap map[string]string
	err = json.NewDecoder(resp.Body).Decode(&wxMap)
	if err != nil {
		api.FailCodeMsgAny(901, "", ctx)
		return
	}
	defer resp.Body.Close()
	api.OK(wxMap, ctx)
}

/*
*
下单逻辑
*/
func (web *WeixinJSPayApi) WeixinPay_JSAPI_SMALL(gctx *gin.Context) {

	params := Params{}
	err2 := gctx.ShouldBindJSON(&params)
	if err2 != nil {
		web.FailCodeMsg(601, "参数传递有误", gctx)
		return
	}

	fmt.Println("你要支付的产品是：params", params.GoodsId)

	var (
		mchID                      string = "1615158475"                               // 商户号
		mchCertificateSerialNumber string = "61B27028E8DDBA019C55791F9D12F52DEF84A862" // 商户证书序列号
		mchAPIv3Key                string = "0139a6d9e93fb88d3d68e0a8a1b06bd6"         // 商户APIv3密钥
	)
	// 使用 utils 提供的函数从本地文件中加载商户私钥，商户私钥会用来生成请求的签名
	mchPrivateKey, err := utils.LoadPrivateKeyWithPath("F:/paykey/apiclient_key.pem")
	if err != nil {
		log.Print("load merchant private key error")
	}

	ctx := context.Background()
	// 使用商户私钥等初始化 client，并使它具有自动定时获取微信支付平台证书的能力
	opts := []core.ClientOption{
		option.WithWechatPayAutoAuthCipher(mchID, mchCertificateSerialNumber, mchPrivateKey, mchAPIv3Key),
	}
	client, err := core.NewClient(ctx, opts...)
	if err != nil {
		log.Printf("new wechat pay client err:%s", err)
	}
	// 雪花算法生成的订单编号
	worker, _ := utils2.NewWorker(1)
	OutTradeNo := worker.NextId()

	svc := jsapi.JsapiApiService{Client: client}
	resp, result, err := svc.Prepay(ctx,
		jsapi.PrepayRequest{
			Appid:       core.String("wx2130f87b8f96cff7"),
			Mchid:       core.String("1615158475"),
			Description: core.String("Image形象店-深圳腾大-QQ公仔"),
			OutTradeNo:  core.String(OutTradeNo),
			TimeExpire:  core.Time(time.Now()),
			Attach:      core.String("{'userId':1000}"),
			NotifyUrl:   core.String("http://feifei.free.idcfengye.com/api/v1/wxpay/small/callback"),
			Amount: &jsapi.Amount{
				Currency: core.String("CNY"),
				Total:    core.Int64(1), // 单分 100分 = 1  1.23==123
			},
			Payer: &jsapi.Payer{
				Openid: core.String(params.OpenId),
			},
		},
	)

	if err != nil {
		// 处理错误
		web.FailCodeMsg(601, "支付失败", gctx)
		return
	}
	// 处理返回结果
	log.Printf("status=%d resp=%s", result.Response.StatusCode, resp)
	info := tools.SmallAppOrderInfo(*resp.PrepayId, OutTradeNo, mchPrivateKey)
	web.OK(info, gctx)

}

/*
*
查单
*/
func (web *WeixinJSPayApi) WeixinPay_QueryOrderByOutTradeNo(gctx *gin.Context) {

	params := QueryParams{}
	err2 := gctx.ShouldBindJSON(&params)
	if err2 != nil {
		web.FailCodeMsg(601, "参数有误", gctx)
		return
	}

	fmt.Println("你要查询的编号是：", params.OutTradeNo)

	var (
		mchID                      string = "1615158475"                               // 商户号
		mchCertificateSerialNumber string = "61B27028E8DDBA019C55791F9D12F52DEF84A862" // 商户证书序列号
		mchAPIv3Key                string = "0139a6d9e93fb88d3d68e0a8a1b06bd6"         // 商户APIv3密钥
	)

	// 使用 utils 提供的函数从本地文件中加载商户私钥，商户私钥会用来生成请求的签名
	mchPrivateKey, err := utils.LoadPrivateKeyWithPath("F:/paykey/apiclient_key.pem")
	if err != nil {
		log.Print("load merchant private key error")
	}

	ctx := context.Background()
	// 使用商户私钥等初始化 client，并使它具有自动定时获取微信支付平台证书的能力
	opts := []core.ClientOption{
		option.WithWechatPayAutoAuthCipher(mchID, mchCertificateSerialNumber, mchPrivateKey, mchAPIv3Key),
	}
	client, err := core.NewClient(ctx, opts...)
	if err != nil {
		log.Printf("new wechat pay client err:%s", err)
	}

	svc := jsapi.JsapiApiService{Client: client}
	resp, _, err := svc.QueryOrderByOutTradeNo(ctx,
		jsapi.QueryOrderByOutTradeNoRequest{
			OutTradeNo: core.String(params.OutTradeNo),
			Mchid:      core.String(mchID),
		},
	)

	if err != nil {
		// 处理错误
		web.FailCodeMsg(601, "查单失败", gctx)
		return
	}

	if *resp.TradeState == "SUCCESS" {
		// 肯定就执行一个，根据订单编号修改订单支付状态
		// orderservice.updateByOutradeNo(params.OutTradeNo)
		web.OK("SUCCESS", gctx)
	}
}

/*
*
支付回调地址--
*/
func (web *WeixinJSPayApi) WeixinPay_JSAPI_CALLBACK(ctx *gin.Context) {
	fmt.Println("那些非正常的这行处理，进入这里了....")
	fmt.Println("微信支付回调进来了")
	defer func() {
		if err := recover(); err != nil {
			fmt.Println("支付宝：数据已保存！")
			web.OK("ok", ctx)
		}
	}()
	// 获取你支付的回调参数, 也就是说微信服务器会把你所有的订单信息放入到请求体
	bodydata, _ := ioutil.ReadAll(ctx.Request.Body)
	request := notify.Request{}
	// 开始解析你的请求体的参数
	param := string(bodydata)
	// 把请求体参数转换request对象
	tools.JsontoStruct(param, &request)
	// 准备一个map获取request中的参数信息
	tmp := make(map[string]interface{})
	// 判断当前交易是否是成功的
	if request.EventType == "TRANSACTION.SUCCESS" {
		fmt.Println("微信支付回调进来了，支付成功!!")
		mchAPIv3Key := "0139a6d9e93fb88d3d68e0a8a1b06bd6"
		// 把请求体中订单的数据信息获取出来。也就是request.Resource.AssociatedData, 然后通过DecryptAES256GCM的方法就RSA解密，然后得到一个json字符串
		plaintext, _ := utils.DecryptAES256GCM(mchAPIv3Key, request.Resource.AssociatedData, request.Resource.Nonce, request.Resource.Ciphertext)
		// 把获取json字符串转成Transaction对象
		transaction := payments.Transaction{}
		tools.JsontoStruct(plaintext, &transaction)
		// 这里就是解析下单的附属参数
		attchParams := AttchParams{}
		tools.JsontoStruct(*transaction.Attach, &attchParams)
		fmt.Println("微信支付回调进来了，参数获取：", attchParams)
		//微信支付回调返回特殊处理，Flag = 40
		tmp["code"] = "SUCCESS"
		tmp["message"] = "成功"

		// 根据交易编号订单状态修改
		// orderservice.updateByOutradeNo(transaction.OutTradeNo)
	} else {
		tmp["code"] = "500"
		tmp["message"] = "失败"
	}
	web.OK(tmp, ctx)

}
